﻿using System.Collections.Generic;

namespace Gamelight.Graphics.SpriteSheet
{
	internal class SpriteGroup
	{
		private string name;
		private int maxHeight = 0;
		private int maxWidth = 0;

		private List<Image> images = new List<Image>();
		private List<int> xOffsets = new List<int>();
		private List<int> yOffsets = new List<int>();
		private bool arrayAccessorValid = false;
		private Image[] imageArray;

		public SpriteGroup(SpriteGroup groupToCopy, bool flipHorizontally)
		{
			this.name = groupToCopy.Name;
			this.maxHeight = groupToCopy.maxHeight;
			this.maxWidth = groupToCopy.maxWidth;

			for (int i = 0; i < groupToCopy.images.Count; ++i)
			{
				Image image = flipHorizontally
					? Transformation.FlipHorizontally(groupToCopy.images[i])
					: Transformation.FlipVertically(groupToCopy.images[i]);
				
				this.images.Add(image);
				this.xOffsets.Add((flipHorizontally ? -1 : 1) * groupToCopy.xOffsets[i]);
				this.yOffsets.Add((flipHorizontally ? 1 : -1) * groupToCopy.yOffsets[i]);
			}
		}

		public SpriteGroup(string name)
		{
			this.name = name;
		}

		public string Name
		{
			get { return this.name; }
		}

		public Image[] Images
		{
			get
			{
				if (!this.arrayAccessorValid)
				{
					this.imageArray = images.ToArray();
				}
				return this.imageArray;
			}
		}

		internal void AddSprite(Image image, Direction direction, int xOffset, int yOffset)
		{
			this.images.Add(image);
			this.xOffsets.Add(xOffset);
			this.yOffsets.Add(yOffset);

			image.XOffset = xOffset;
			image.YOffset = yOffset;

			if (image.Height > this.maxHeight)
			{
				this.maxHeight = image.Height;
			}

			if (image.Width > this.maxWidth)
			{
				this.maxWidth = image.Width;
			}
		}

		internal void AlignBottom()
		{
			for (int i = 0; i < this.images.Count; ++i)
			{
				Image image = this.images[i];
				int yOffset = this.yOffsets[i];
				image.YOffset = this.maxHeight - image.Height + yOffset;
			}
		}

		internal void AlignRight()
		{
			for (int i = 0; i < this.images.Count; ++i)
			{
				Image image = this.images[i];
				int xOffset = this.xOffsets[i];
				image.XOffset = this.maxWidth - image.Width + xOffset;
			}
		}

		internal void AlignTop()
		{
			for (int i = 0; i < this.images.Count; ++i)
			{
				Image image = this.images[i];
				int yOffset = this.yOffsets[i];
				image.YOffset = yOffset;
			}
		}

		internal void AlignLeft()
		{
			for (int i = 0; i < this.images.Count; ++i)
			{
				Image image = this.images[i];
				int xOffset = this.xOffsets[i];
				image.XOffset = xOffset;
			}
		}

		internal void HorizontallyCenter()
		{
			for (int i = 0; i < this.images.Count; ++i)
			{
				Image image = this.images[i];
				int xOffset = this.xOffsets[i];
				image.XOffset = -image.Width / 2 + xOffset;
			}
		}

		internal void VerticallyCenter()
		{
			for (int i = 0; i < this.images.Count; ++i)
			{
				Image image = this.images[i];
				int yOffset = this.yOffsets[i];
				image.YOffset = -image.Height / 2 + yOffset;
			}
		}

		public static void AutodetectCollectiveHorizontalOffsets(params SpriteGroup[] groups)
		{
			List<Image> images = new List<Image>();
			List<int> xOffsets = new List<int>();
			List<int> yOffsets = new List<int>();

			foreach (SpriteGroup group in groups)
			{
				images.AddRange(group.images);
				xOffsets.AddRange(group.xOffsets);
				yOffsets.AddRange(group.yOffsets);
			}

			int largestOffset = 0;
			foreach (Image image in images)
			{
				int[] pixels = image.Pixels;
				int width = image.Width;
				int height = image.Height;
				int pixelCount = 0;
				int weight = 0;
				int y;
				for (int x = 0; x < width; ++x)
				{
					for (y = 0; y < height; ++y)
					{
						if (pixels[y * width + x] != 0)
						{
							pixelCount++;
							weight += x;
						}
					}
				}

				int centerX = weight / pixelCount;
				if (centerX > largestOffset)
				{
					largestOffset = centerX;
				}
				image.XOffset = -centerX;
			}

			for (int i = 0; i < images.Count; ++i)
			{
				Image image = images[i];
				image.XOffset += xOffsets[i];
				image.YOffset += yOffsets[i];
			}
		}

		internal void AutodetectHorizontalOffsets()
		{
			SpriteGroup.AutodetectCollectiveHorizontalOffsets(this);
		}

		internal void AutodetectVerticalOffsets()
		{
			this.AlignBottom(); // This is the best I can think of. :\
		}

		internal SpriteGroup Flip(bool flipHorizontally)
		{
			return new SpriteGroup(this, flipHorizontally);
		}
	}
}
